#include <sstream>
#include <iostream>

#include "utility.hpp"

#include "config.hpp"
#include "config_base.hpp"

#include "config_mgr.hpp"

const std::string ConfSvrConf::to_string() const
{
	std::ostringstream oss;
	oss << "{common: " << _common.to_string()
		<< ", service: " << _service.to_string()
		<< "}";
	return oss.str();
}

#define LOAD_CONF \
	Config config; \
	if (config.load(pathname) < 0) \
	{ \
		LOG4CPLUS_ERROR(logger, "config load file error. pathname: " << pathname); \
		return -1; \
	}

#define LOAD_SVR_CONF(function, pathname) \
	if (function(pathname) != 0) \
	{ \
		LOG4CPLUS_ERROR(logger, "" << #function << " failed. pathname: " << pathname); \
		return -1; \
	}

#define GET_COMMON_CONF(config, comm) \
	{ \
		get_param_size(config, "FIXED_SIZE_ALLOCATOR", "page.size", comm._fixed_page_size, false); \
		get_param_size(config, "FIXED_SIZE_ALLOCATOR", "capacity.size", comm._fixed_capacity_size, false); \
		get_param_int(config, "FIXED_SIZE_ALLOCATOR", "max_connection", comm._max_connection, false); \
		get_param_int(config, "FIXED_SIZE_ALLOCATOR", "epoll_timeout", comm._epoll_timeout, false); \
	}

IMPL_LOGGER(ConfigMgr, logger);

const static std::string CONFSVR_CONF       = "../conf/confsvr.conf";
const static std::string DBSVR_CONF         = "../conf/dbsvr.conf";
const static std::string BALANCE_CONF       = "../conf/balance.conf";
const static std::string ACCOUNT_CONF       = "../conf/account.conf";
const static std::string GATEWAY_CONF       = "../conf/gateway.conf";
const static std::string SCENCE_CONF        = "../conf/scence.conf";
const static std::string HTTP_CLIENT_CONF   = "../conf/http_client.conf";

int ConfigMgr::load()
{
	LOAD_SVR_CONF(load_confsvr,       CONFSVR_CONF);
	LOAD_SVR_CONF(load_dbsvr,         DBSVR_CONF);
	LOAD_SVR_CONF(load_balance,       BALANCE_CONF);
	LOAD_SVR_CONF(load_account,       ACCOUNT_CONF);
	LOAD_SVR_CONF(load_gateway,       GATEWAY_CONF);
	LOAD_SVR_CONF(load_scence,        SCENCE_CONF);
	LOAD_SVR_CONF(load_http_client,   HTTP_CLIENT_CONF);

	display();

	return 0;
}

int ConfigMgr::load_confsvr(const std::string & pathname)
{
	LOAD_CONF;

	GET_COMMON_CONF(config, _confsvr._common);

	std::string ip;

	get_param_str(config, "SERVICE", "ip", ip, false);
	_confsvr._service._ip = ip; // Utility::ip_aton(ip.c_str());
	get_param_int(config, "SERVICE", "port", _confsvr._service._port, false);

	return 0;
}

int ConfigMgr::load_dbsvr(const std::string   & pathname)
{
	LOAD_CONF;

	DBSvrConf dbsvr;

	GET_COMMON_CONF(config, dbsvr._common);

	get_param_int(config, "DBSVR_COMMON", "thread_num", dbsvr._thread_num, false);
	get_param_int(config, "DBSVR_COMMON", "queue_size", dbsvr._thread_queue_size, false);
	get_param_size(config, "DBSVR_COMMON", "page.size", dbsvr._thread_page_size, false);
	get_param_size(config, "DBSVR_COMMON", "capacity.size", dbsvr._thread_capacity_size, false);

	int dbsvr_num = 0;
	get_param_int(config, "DBSVR_COMMON", "dbsvr_num", dbsvr_num, false);

	std::ostringstream oss;

	std::string ip;
	uint32_t id = 0;
	
	for (int i = 0; i < dbsvr_num; ++ i)
	{
		oss.str("");
		oss << "DBSVR_" << (i + 1);
		
		std::string section = oss.str();

		get_param_int(config, section.c_str(), "id", id, false);
		
		get_param_str(config, section.c_str(), "ip", ip, false);
		get_param_int(config, section.c_str(), "port", dbsvr._service._port, false);
		dbsvr._service._ip  = ip; // Utility::ip_aton(ip.c_str());

		get_param_str(config, section.c_str(), "host", ip, false);
		dbsvr._mysql_host  = ip; // Utility::ip_aton(ip.c_str());
		get_param_str(config, section.c_str(), "user", dbsvr._mysql_user, false);
		get_param_str(config, section.c_str(), "passwd", dbsvr._mysql_passwd, false);
		get_param_str(config, section.c_str(), "dbname", dbsvr._mysql_dbname, false);

		if (!_dbsvr_map.insert(std::make_pair(id, dbsvr)).second)
		{
			LOG4CPLUS_ERROR(logger, "dupliacate dbsvr id. id: " << id << ", pathname: " << pathname);
			assert(false);
		}
	}

	return 0;
}

int ConfigMgr::load_balance(const std::string & pathname)
{
	LOAD_CONF;

	GET_COMMON_CONF(config, _balance._common);

	std::string ip;
	get_param_str(config, "BALANCE", "ip", ip, false);
	
	_balance._service._ip  = ip; // Utility::ip_aton(ip.c_str());

	get_param_int(config, "BALANCE", "port", _balance._service._port, false);

	return 0;
}

int ConfigMgr::load_account(const std::string & pathname)
{
	LOAD_CONF;

	GET_COMMON_CONF(config, _account._common);

	std::string ip;

	get_param_str(config, "ACCOUNT", "ip", ip, false);
	_account._service._ip   = ip; // Utility::ip_aton(ip.c_str());
	get_param_int(config, "ACCOUNT", "port", _account._service._port, false);

	int dbsvr_id = 0;
	get_param_int(config, "ACCOUNT", "dbsvr_id", dbsvr_id, false);

	DBSvrConfMap_Iter iter = _dbsvr_map.find(dbsvr_id);

	if (_dbsvr_map.end() == iter)
	{
		LOG4CPLUS_ERROR(logger, "not found dbsvr id. dbsvr_id: " << dbsvr_id << ", pathname: " << pathname);
		assert(false);
	}

	_account._dbsvr   = iter->second._service;

	return 0;
}

int ConfigMgr::load_http_client(const std::string  & pathname)
{
	LOAD_CONF;

	GET_COMMON_CONF(config, _http_client._common);

	std::string ip;

	get_param_str(config, "HTTP_CLIENT", "ip", ip, false);
	_account._service._ip   = ip; // Utility::ip_aton(ip.c_str());
	
	get_param_int(config, "HTTP_CLIENT", "port", _http_client._service._port, false);

	get_param_str(config, "TENCENT", "url", _http_client._url, false);
	get_param_str(config, "TENCENT", "version", _http_client._version, false);
	get_param_str(config, "TENCENT", "appid", _http_client._appid, false);
	get_param_str(config, "TENCENT", "appkey", _http_client._appkey, false);
	get_param_str(config, "TENCENT", "pf", _http_client._pf, false);
	get_param_str(config, "TENCENT", "format", _http_client._format, false);

	get_param_int(config, "THREAD", "thread_num", _http_client._thread_num, false);
	get_param_int(config, "THREAD", "timeout", _http_client._http_timeout, false);

	return 0;
}

int ConfigMgr::load_gateway(const std::string & pathname)
{
	LOAD_CONF;

	GatewayConf gateway;

	GET_COMMON_CONF(config, gateway._common);

	int gateway_num = 0;
	get_param_int(config, "GATEWAY_COMMON", "gateway_num", gateway_num, false);
	get_param_int(config, "GATEWAY_COMMON", "timeout",     gateway._timeout, false);

	std::ostringstream   oss;

	int          id = 0;
	std::string  ip;

	for (int i = 0; i < gateway_num; ++ i)
	{
		oss.str("");
		oss << "GATEWAY_" << (i + 1);

		get_param_int(config, oss.str().c_str(), "id", id, false);

		get_param_str(config, oss.str().c_str(), "scence_ip",   gateway._scence._ip,   false);
		get_param_int(config, oss.str().c_str(), "scence_port", gateway._scence._port, false); 

		get_param_str(config, oss.str().c_str(), "client_ip",   gateway._client._ip,   false);
		get_param_int(config, oss.str().c_str(), "client_port", gateway._client._port, false);

		get_param_str(config, oss.str().c_str(), "http_ip",     gateway._http_client._ip, false);
		get_param_int(config, oss.str().c_str(), "http_port",   gateway._http_client._port, false);

		get_param_str(config, oss.str().c_str(), "dbsvr_ip",    gateway._dbsvr._ip, false);
		get_param_int(config, oss.str().c_str(), "dbsvr_port",  gateway._dbsvr._port, false);

		get_param_str(config, oss.str().c_str(), "balance_ip",   gateway._balance._ip, false);
		get_param_int(config, oss.str().c_str(), "balance_port", gateway._balance._port, false);

		if (!_gateway_map.insert(std::make_pair(id, gateway)).second)
		{
			LOG4CPLUS_ERROR(logger, "duplicate gateway id. id: " << id << ", pathname: " << pathname);
			assert(false);
		}
	}

	return 0;
}

int ConfigMgr::load_scence(const std::string  & pathname)
{
	LOAD_CONF;

	ScenceConf scence;

	GET_COMMON_CONF(config, scence._common); 

	GatewayConfMap_Iter giter = _gateway_map.begin();
	for (; giter != _gateway_map.end(); ++ giter)
	{
		scence._gateway_list.push_back(giter->second._scence);
	}

	int scence_num = 0;
	get_param_int(config, "SCENCE_COMMON", "scence_num", scence_num, false);

	std::ostringstream  oss;
	std::string         section;
	AreaConf            area;

	int id         = 0;
	int dbsvr_id   = 0;
	int area_num   = 0;

	for (int i = 0; i < scence_num; ++ i)
	{
		oss.str("");
		oss << "SCENCE_" << (i + 1);

		section = oss.str();

		get_param_int(config, section.c_str(), "id", id, false);
		get_param_int(config, section.c_str(), "dbsvr_id", dbsvr_id, false);

		DBSvrConfMap_Iter diter = _dbsvr_map.find(dbsvr_id);
		if (_dbsvr_map.end() == diter)
		{
			LOG4CPLUS_ERROR(logger, "nout found dbsvr_id . id: " << dbsvr_id << ", pathname: " << pathname);
			assert(false);
		}
		
		// scence._dbsvr  = diter->second._service;

		get_param_int(config, section.c_str(), "area_num", area_num, false);

		int value = 0;
		for (int j = 0; j < area_num; ++ j)
		{
			oss.str("");
			oss << "area_id_" << (j + 1);
			get_param_int(config, section.c_str(), oss.str().c_str(), value, false);
			area._area_id  = value;
			
			oss.str("");
			oss << "area_type_" << (j + 1);
			get_param_int(config, section.c_str(), oss.str().c_str(), value, false);
			// area._area_type = value;

			oss.str("");
			oss << "room_num_" << (j + 1);
			get_param_int(config, section.c_str(), oss.str().c_str(), value, false);
			area._room_num  = value;

			oss.str("");
			oss << "table_num_" << (j + 1);
			get_param_int(config, section.c_str(), oss.str().c_str(), value, false);
			area._table_num = value;

			scence._area_list.push_back(area);
		}

		if (!_scence_map.insert(std::make_pair(id, scence)).second)
		{
			LOG4CPLUS_ERROR(logger, "duplicate scence id. id: " << id << ", pathname: " << pathname);
			assert(false);
		}
	}

	return 0;
}

void ConfigMgr::display()
{
	LOG4CPLUS_ERROR(logger, "*********** load config file info *********");

	LOG4CPLUS_ERROR(logger, "confsvr: " << _confsvr.to_string());

	std::string conf_str = "";

	for (DBSvrConfMap::iterator iter = _dbsvr_map.begin(); iter != _dbsvr_map.end(); ++ iter)
	{
		conf_str += iter->second.to_string();
	}

	LOG4CPLUS_ERROR(logger, "dbsvr: " << conf_str);

	LOG4CPLUS_ERROR(logger, "balance: " << _balance.to_string());

	LOG4CPLUS_ERROR(logger, "account: " << _account.to_string());

	LOG4CPLUS_ERROR(logger, "httpclient: " << _http_client.to_string());

	conf_str = "";

	for (GatewayConfMap::iterator iter = _gateway_map.begin(); iter != _gateway_map.end(); ++ iter)
	{
		conf_str += iter->second.to_string();
	}

	LOG4CPLUS_ERROR(logger, "gateway: " << conf_str);

	conf_str = "";

	for (ScenceConfMap::iterator iter = _scence_map.begin(); iter != _scence_map.end(); ++ iter)
	{
		conf_str += iter->second.to_string();
	}

	LOG4CPLUS_ERROR(logger, "scence: " << conf_str);

	LOG4CPLUS_ERROR(logger, "*********** load config file info *********");
}

